﻿#ifndef STAGECONTROL_H
#define STAGECONTROL_H
#include <QSettings>
#include <QObject>
#include <QTimer>
#include "motioncontroller.h"
#include "dialog_LECalibrator.h"

const int COUNT = 2;//

class StageControl : public QObject
{
    Q_OBJECT
public:
    explicit StageControl(MotionController *card = 0, QObject *parent = 0);
    void loadSettings(QSettings &settings);
    void writeSettings(QSettings &settings);
    void attach(MotionController * card);
signals:
    void xMoveFinish();
    void yMoveFinish();
    void zMoveFinish();
    void wMoveFinish();

    void xGoHomeFinish();
    void yGoHomeFinish();
    void zGoHomeFinish();
    void wGoHomeFinish();
    void GoHomeFinish();

    void moveToRelativePos_achieve();
    void moveToPos_achieve();
    void updateEncoder(double x_mm, double y_mm);
public slots:
    bool isMoving(unsigned short axis) {return m_card->isMoving(axis);}
    /**
     * @brief setSpeed 设置平台的运行速度
     * @param axis
     * @param mm_per_second  mm/s 为单位的速度
     */
    void setSpeed(unsigned short axis, double mm_per_second);
    /**
     * @brief setXSpeed
     * @param mm_per_second
     */
    void setXSpeed(double mm_per_second);
    void setYSpeed(double mm_per_second);
    void setZSpeed(double mm_per_second);
    /**
     * @brief setDir 设置我们的坐标系统与电机旋转方向的关系
     * @param left 当 X 轴电机正转时如果向左运动，则 left = 1，否则 left = -1
     * @param forward
     * @param up
     */
    void setDir(int left, int forward, int up);

    /**
     * @brief setStepSize 设置各轴运动单位长度时所需的脉冲步数
     * @param x_ppm  X 轴运动 1 mm 所需的脉冲步数
     * @param y_ppm  Y 轴运动 1 mm 所需的脉冲步数
     * @param z_ppm  Z 轴运动 1 mm 所需的脉冲步数
     */
    void setStepSize(double x_ppm, double y_ppm, double z_ppm);

    /**
     * @brief setRuler 设置各轴运动单位长度时编码器输出的脉冲数
     * @param x_pulse   X 轴运动 1 mm 时编码器输出的脉冲数
     * @param y_pulse   Y 轴运动 1 mm 时编码器输出的脉冲数
     * @param z_pulse   Z 轴运动 1 mm 时编码器输出的脉冲数
     */
    void setRuler(int x_pulse, int y_pulse, int z_pulse);

    /**
     * @brief moveToPos 移动到平台上的一个指定位置，单位是毫米
     * @param x_mm
     * @param y_mm
     */
    void xyMoveToPos(double x_mm, double y_mm, double speed = 5.0);
    void zMoveToPos(double z_mm, double speed = 5.0);
    /**
     * @brief moveToRelativePos 以当前位置为参考原点，移动到平台上的一个指定位置，单位是毫米
     * @param x_mm
     * @param y_mm
     */
    void xyMoveToRelativePos(double x_mm, double y_mm, double speed = 5.0);
    void zMoveToRelativePos(double z_mm, double speed = 5.0);

    /**
     * @brief moveToRelativePos 以当前位置为参考原点，移动到平台上的一个指定位置，单位是毫米
     * @param x_mm
     * @param y_mm
     * @param y_mm
     */
    void moveToRelativePos(double x_mm, double y_mm, double z_mm, double speed = 5.0);
    /**
     * @brief moveToPos 以当前位置为参考原点，移动到平台上的一个指定位置，单位是毫米
     * @param x_mm
     * @param y_mm
     * @param y_mm
     */
    void moveToPos(double x_mm, double y_mm, double z_mm, double speed = 5.0);

    ///@brief moveBackward 显微镜向后运动
    void moveBackward();
    void moveBackward(double speed);
    ///@brief moveForward  显微镜向后运动
    void moveForward();
    void moveForward(double speed);
    ///@brief moveUp  显微镜向上运动
    void moveUp();
    void moveUp(double speed);
    ///@brief moveDown  显微镜向下运动
    void moveDown();
    void moveDown(double speed);
    ///@brief moveLeft  显微镜向左运动
    void moveLeft();
    void moveLeft(double speed);
    ///@brief moveRight 显微镜向右运动
    void moveRight();
    void moveRight(double speed);
    ///@brief stopX 停止 X 轴运动
    void stopX();

    ///@brief stopY 停止 Y 轴运动
    void stopY();

    ///@brief stopZ 停止 Z 轴运动
    void stopZ();

    ///@brief stop 停止所有运动
    void stop();

    ///@brief goHomeX X 轴回到零位
    void goHomeX();

    ///@brief goHomeY Y 轴回到零位
    void goHomeY();

    ///@brief goHomeZ Z 轴回到零位
    void goHomeZ();

    ///@brief goHome ZXY 轴按顺序回到零位
    void goHome();

    /**
     * @brief updatePos 更新当前位置（单位 mm），并通过两个数组将各个位置输出出来
     * @param theoryPos_mm
     * @param encodePos_mm
     */
    void updatePos(double theoryPos_mm[], double encodePos_mm[]);

    /**
     * @brief updateInputIO 更新IO口的输入
     * @param io
     */
    void updateInputIO(bool io[]);

    /**
     * @brief LECalibrator_show 光栅尺矫正
     */
    void LECalibrator_show();

private:
    void updatetheoryPos2encodePos();
    void encode2ruler(double xEncode, double yEncode, double &xRuler, double &yRuler);
    void ruler2encode(double xRuler, double yRuler, double &xEncode, double &yEncode);
private:
    /// 标志平台运动的各个方向
    int m_dir_left;
    int m_dir_right;
    int m_dir_up;
    int m_dir_down;
    int m_dir_forward;
    int m_dir_backward;

    int m_speed[4];
    int m_goHomeSpeed[4];

    double m_theoryPos_mm[4];
    double m_encodePos_mm[4];

    //X、Y、Z 三轴行走 1 毫米所需的脉冲数
    double m_pulse_per_millimeter[3];
    // 光栅尺每毫米的脉冲数
    double m_ruler_pulse_per_millimeter[4];

    MotionController * m_card;


    /// XYZW 回原点时利用这四个定时器来等待操作完成
    QTimer *m_timerHome;

    QTimer *m_timerXYZMove;

    bool m_xIsMoving;
    bool m_yIsMoving;
    bool m_zIsMoving;
    bool m_wIsMoving;

    bool m_xIsGoingHome;
    bool m_yIsGoingHome;
    bool m_zIsGoingHome;
    bool m_wIsGoingHome;
    bool m_allIsGoingHome;

    //相对运动
    QTimer *m_timerXYZPos;
    double x_END;
    double y_END;
    double z_END;
    double x_theoryPos2encodePos;
    double y_theoryPos2encodePos;
    double z_theoryPos2encodePos;
    int m_count;

    //光栅尺矫正
    Dialog_LECalibrator m_LEC;
    LEData ledata_x;
    LEData ledata_y;
    LECalibrator lec_x;
    LECalibrator lec_y;

private slots:
    void waitForGoHome();
    void waitForMoveToPos();
    //COUNT次内等待编码器返回误差在0.001mm以内停止
    void waitForPos();
};

#endif // STAGECONTROL_H
